﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SqlServer.Management.UI.VSIntegration.ObjectExplorer;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Data;
using Microsoft.SqlServer.Management.UI.VSIntegration;
using System.Text.RegularExpressions;
using Microsoft.AnalysisServices;
using EnvDTE;

namespace SSMS_Scripter
{
    /// <summary>
    /// Represents the menu item added for processing options
    /// </summary>
    public class MenuItem : ToolsMenuItemBase, IWinformsMenuHandler
    {
        #region Fields
        private bool cubeOptionsEnabled;
        private bool dimOptionsEnabled;

        public string dimProcess =
            @"
    <Process xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:ddl2=""http://schemas.microsoft.com/analysisservices/2003/engine/2"" 
            xmlns:ddl2_2=""http://schemas.microsoft.com/analysisservices/2003/engine/2/2"" xmlns:ddl100_100=""http://schemas.microsoft.com/analysisservices/2008/engine/100/100"">
      <Object>
        <DatabaseID>@Database</DatabaseID>
        <DimensionID>@Dim</DimensionID>
      </Object>
      <Type>ProcessFull</Type>
      <WriteBackTableCreation>UseExisting</WriteBackTableCreation>
    </Process>";

        public string cubeProcess =
            @"
    <Process xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:ddl2=""http://schemas.microsoft.com/analysisservices/2003/engine/2"" 
            xmlns:ddl2_2=""http://schemas.microsoft.com/analysisservices/2003/engine/2/2"" xmlns:ddl100_100=""http://schemas.microsoft.com/analysisservices/2008/engine/100/100"">
      <Object>
        <DatabaseID>@Database</DatabaseID>
        <CubeID>@Cube</CubeID>
      </Object>
      <Type>ProcessFull</Type>
      <WriteBackTableCreation>UseExisting</WriteBackTableCreation>
    </Process>";

        public string processStart =
            @"<Batch xmlns=""http://schemas.microsoft.com/analysisservices/2003/engine"">
  <Parallel>";
        public string processEnd =
            @"
  </Parallel>
</Batch>";
        public string database;

        #endregion

        /// <summary>
        /// Constructor for process menu item
        /// </summary>
        /// <param name="cube">True if cube options should be displayed</param>
        /// <param name="dim">True if dimension options should be displayed</param>
        public MenuItem(bool cube, bool dim)
        {
            this.Text = "Process...";
            cubeOptionsEnabled = cube;
            dimOptionsEnabled = dim;
        }

        public void GetDatabaseInfo()
        {
            database = GetDBName(this.Parent.Context);
        }

        protected override void Invoke()
        {
        }

        /// <summary>
        /// Handles duplication
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new MenuItem(cubeOptionsEnabled, dimOptionsEnabled);
        }

        #region IWinformsMenuHandler Members

        /// <summary>
        /// Returns list of items in context menu
        /// </summary>
        /// <returns></returns>
        public System.Windows.Forms.ToolStripItem[] GetMenuItems()
        {
            ToolStripMenuItem item = new ToolStripMenuItem("Process...");
            ToolStripMenuItem insertItem;

            // Add cube options (if enabled)
            if (cubeOptionsEnabled)
            {
                insertItem = new ToolStripMenuItem("All Cubes");
                insertItem.Click += new EventHandler(AllCube_Click);
                item.DropDownItems.Add(insertItem);

                insertItem = new ToolStripMenuItem("Cubes...");
                insertItem.Click += new EventHandler(Cubes_Click);
                item.DropDownItems.Add(insertItem);
            }

            // Add dimension options (if enabled)
            if (dimOptionsEnabled)
            {
                insertItem = new ToolStripMenuItem("All Dimensions");
                insertItem.Click += new EventHandler(AllDim_Click);
                item.DropDownItems.Add(insertItem);

                insertItem = new ToolStripMenuItem("Dimensions...");
                insertItem.Click += new EventHandler(Dimensions_Click);
                item.DropDownItems.Add(insertItem);
            }

            return new ToolStripItem[] { item };
        }

        #endregion

        /// <summary>
        /// Returns match for database based on current context
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        protected string GetDBName(string context)
        {
            Regex dbRegex = new Regex(@"^OlapServer\[[^\]]*\]/Database\[@ID='(?<Database>[^']*)'\]");
            return dbRegex.Match(context).Groups["Database"].Value;
        }

        /// <summary>
        /// Gets list of cubes for established connection
        /// </summary>
        /// <param name="sender"></param>
        /// <returns></returns>
        public List<string> GetCubes(object sender)
        {
            List<string> result = new List<string>();
            ToolStripMenuItem item = (ToolStripMenuItem)sender;

            Regex dbRegex = new Regex(@"^OlapServer\[[^\]]*\]/Database\[[^=]*='(?<Database>[^']*)'\]");
            Match match = dbRegex.Match(this.Parent.Context);
            if (match != null)
            {
                string connectionString = this.Parent.Connection.ConnectionString + ";Database=" + database;
                Server s = new Server();
                s.Connect(connectionString);

                foreach (Cube c in s.Databases[database].Cubes)
                {
                    result.Add(c.ID);
                }
            }
            return result;
        }

        /// <summary>
        /// Gets list of dimensions for established connection
        /// </summary>
        /// <param name="sender"></param>
        /// <returns></returns>
        public List<string> GetDims(object sender)
        {
            List<string> result = new List<string>();
            ToolStripMenuItem item = (ToolStripMenuItem)sender;

            Regex dbRegex = new Regex(@"^OlapServer\[[^\]]*\]/Database\[[^=]*='(?<Database>[^']*)'\]");
            Match match = dbRegex.Match(this.Parent.Context);
            if (match != null)
            {
                string connectionString = this.Parent.Connection.ConnectionString + ";Database=" + database;
                Server s = new Server();
                s.Connect(connectionString);

                foreach (Dimension d in s.Databases[database].Dimensions)
                {
                    result.Add(d.ID);
                }
            }
            return result;
        }

        /// <summary>
        /// Handles click for processing the whole cube
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void AllCube_Click(object sender, EventArgs e)
        {
            GetDatabaseInfo();
            string result = "";
            List<string> cubes = GetCubes(sender);

            if (cubes.Count > 0)
            {
                foreach (string s in cubes)
                    result += cubeProcess.Replace("@Database", database).Replace("@Cube", s);

                CreateProcessTask(result);
            }
        }

        /// <summary>
        /// Handles a click for bringing up the cube process dialog
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Cubes_Click(object sender, EventArgs e)
        {
            GetDatabaseInfo();
            ShowProcessList(sender, false);
        }

        /// <summary>
        /// Handles a click for processing all dimensions
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void AllDim_Click(object sender, EventArgs e)
        {
            GetDatabaseInfo();
            string result = "";
            List<string> dims = GetDims(sender);

            if(dims.Count > 0)
            {
                foreach (string s in dims)
                    result += dimProcess.Replace("@Database", database).Replace("@Dim", s);

                CreateProcessTask(result);
            }
        }

        /// <summary>
        /// Handles a click for brining up the dimension processing dialogs
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Dimensions_Click(object sender, EventArgs e)
        {
            GetDatabaseInfo();
            ShowProcessList(sender, true);
        }

        /// <summary>
        /// Shows dialog with process list
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="processDims"></param>
        private void ShowProcessList(object sender, bool processDims)
        {
            if (processDims)
            {
                ProcessDims pc = new ProcessDims(this, sender);
                pc.ShowDialog();
            }
            else
            {
                ProcessCubes pc = new ProcessCubes(this, sender);
                pc.ShowDialog();
            }
        }

        /// <summary>
        /// Create processing task from query
        /// </summary>
        /// <param name="query">XMLA query, not including the start / end processing nodes</param>
        public void CreateProcessTask(string query)
        {
            string result;
            result = processStart;
            result += query;
            result += processEnd;

            LoadXMLADocument(result);
        }

        /// <summary>
        /// Loads given query into new XMLA document
        /// </summary>
        /// <param name="strQuery"></param>
        protected void LoadXMLADocument(string strQuery)
        {
            // create new document
            ServiceCache.ScriptFactory.CreateNewBlankScript(Microsoft.SqlServer.Management.UI.VSIntegration.Editors.ScriptType.Xmla);

            // insert SQL definition to document
            EnvDTE.TextDocument doc = (EnvDTE.TextDocument)ServiceCache.ExtensibilityModel.Application.ActiveDocument.Object(null);
            doc.EndPoint.CreateEditPoint().Insert(strQuery);

            // Uncomment to run the script immediately after creation
            //doc.DTE.ExecuteCommand("Query.Execute", "");
        }

    }
}
